#include "mystdio.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <malloc.h>
#include <assert.h>

MY_FILE *my_fopen(const char *path, const char *mode)
{
    // 1.识别标志位
    int flag = 0;
    if (strcmp(mode, "r") == 0)
        flag |= O_RDONLY;
    else if (strcmp(mode, "w") == 0)
        flag |= (O_CREAT | O_WRONLY | O_TRUNC);
    else if (strcmp(mode, "a") == 0)
        flag |= (O_CREAT | O_WRONLY | O_APPEND);
    else
    {
        // other operator
        //"r+","w+"....
    }

    // 2.尝试打开文件
    mode_t m = 0666;
    int fd = 0;
    if (flag & O_CREAT)
        fd = open(path, flag, m);
    else
        fd = open(path, flag);
    if (fd < 0)
        return NULL;

    // 3.给用户返回MY_FILE对象，需要先进行构建
    MY_FILE *mf = (MY_FILE *)malloc(sizeof(MY_FILE));
    if (mf == NULL)
    {
        close(fd);
        return NULL;
    }

    // 4.初始化MY_FILE对象
    mf->fd = fd;
    mf->flag = 0;
    mf->flag |= BUFF_LINE;
    memset(mf->outputbuffer, '\0', sizeof(mf->outputbuffer)); // 对缓冲区清零
    mf->current = 0;                                          // 缓冲区里没有数据
    // mf->outputbuffer[0] = 0; // 初始化缓冲区

    // 5.返回打开文件
    return mf;
}

int my_fflush(MY_FILE *fp)
{
    assert(fp);
    write(fp->fd, fp->outputbuffer, fp->current);
    fp->current = 0;

    fsync(fp->fd);//将文件描述符强制刷新到外设中
    return 0;
}

// 我们今天返回的就是一次实际写入的字节数，我就不返回个数了
size_t my_fwrite(const void *ptr, size_t size, size_t nmemb, MY_FILE *stream)
{
    // 1.缓冲区如果已经满了，就直接写入
    if (stream->current == NUM) // 说明缓冲区满了
        my_fflush(stream);

    // 2.根据缓冲区剩余情况，进行数据拷贝即可
    size_t user_size = size * nmemb;
    size_t my_size = NUM - stream->current; // 100-10=90

    size_t writen = 0;
    if (my_size >= user_size)
    {
        memcpy(stream->outputbuffer + stream->current, ptr, user_size);
        // 3.更新计数器字段
        stream->current += user_size;
        writen = user_size;
    }
    else
    {
        memcpy(stream->outputbuffer + stream->current, ptr, my_size);
        // 3.更新计数器字段
        stream->current += my_size;
        writen = my_size;
    }

    // 4.开始计划刷新,他们的高效体现在哪里
    if (stream->flag & BUFF_ALL)
    {
        if (stream->current == NUM)
            my_fflush(stream);
    }
    else if (stream->flag & BUFF_LINE)
    {
        if (stream->outputbuffer[stream->current - 1] == '\n')
            my_fflush(stream);
    }
    else
    {
        // my_fflush(stream);
    }
    return writen;
}

int my_fclose(MY_FILE *fd)
{
    assert(fd);
    // 1.冲刷缓冲区
    if (fd->current > 0)
        my_fflush(fd);
    // 2.关闭文件
    close(fd->fd);
    // 3.释放堆空间
    free(fd);
    // 4.指针置NULL--可以设置
    fd = NULL;
    return 0;
}

// int my_scanf(); stdin->buffer->对buffer内容进行格式化，写到对应的变量中
// int a,b; scanf("%d %d",&a, &b); read(0,stdin->buffer,num); -> 123 456 -> 输入的本质：输入的也是字符
//扫描字符串，碰到空格，字符串分割成为两个子串，*ap=atoi(str1);*bp=atoi(str2)

// int my_printf(const char *format,...)
// {
//     //1.先获取对应的变量
//     //2.定义缓冲区，对a转成字符串
//     //2.1 fwrite(stdout,str);
//     //3.将字符串拷贝的stdout->buffer,即可
//     //4.结合刷新策略显示即可
// }